home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / SMTPCLI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-18  |  19.1 KB  |  884 lines

  1. /*
  2.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #ifdef UNIX
  18. #include <sys/types.h>
  19. #endif
  20. #include "global.h"
  21. #include "mbuf.h"
  22. #include "cmdparse.h"
  23. #include "proc.h"
  24. #include "socket.h"
  25. #include "timer.h"
  26. #include "netuser.h"
  27. #include "smtp.h"
  28.  
  29. extern char Badhost[];
  30. extern char *Tcpstates[];
  31. FILE *tmpfile();
  32. time_t time();
  33. static void smtp_send();
  34.  
  35. static struct timer smtpcli_t;
  36. static int32 gateway;
  37.  
  38. #ifdef SMTPTRACE
  39. int    Smtptrace = 0;            /* used for trace level */
  40. static int dosmtptrace();
  41. #endif
  42.  
  43. static int smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  44. static int smtpsessions = 0;        /* number of client connections
  45.                     * currently open */
  46. int    Smtpmode = 0;
  47.  
  48. static struct smtpcli *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  49.  
  50. static char quitcmd[] = "QUIT\r\n";
  51. static char eom[] = "\r\n.\r\n";
  52.  
  53. static int dogateway(),dosmtpmaxcli(),dotimer(),next_job(), setsmtpmode();
  54. static int sendfile();
  55. int smtptick(), dosmtp(), mlock(), rmlock();
  56. static void sendquit(),abort_trans(),retmail(),sendcmd();
  57. static void del_session(),del_job(), execjobs(),logerr();
  58. static struct smtpcli *newcb(),*lookup();
  59. static struct smtp_job *setupjob();
  60.  
  61. struct cmds smtpcmds[] = {
  62.     "gateway",    dogateway,    0,    0,    NULLCHAR,
  63.     "mode",        setsmtpmode,    0,    0,    NULLCHAR,
  64.     "kick",        smtptick,    0,    0,    NULLCHAR,
  65.     "maxclients",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  66.     "timer",    dotimer,    0,    0,    NULLCHAR,
  67. #ifdef SMTPTRACE
  68.     "trace",    dosmtptrace,    0,    0,    NULLCHAR,
  69. #endif
  70.     NULLCHAR,    NULLFP,        0,    0,    
  71.     "subcommands: gateway kick maxclients timer trace",
  72.         NULLCHAR,
  73. };
  74.  
  75. int
  76. dosmtp(argc,argv)
  77. int argc;
  78. char *argv[];
  79. {
  80.     return subcmd(smtpcmds,argc,argv);
  81. }
  82.  
  83. static int
  84. dosmtpmaxcli(argc,argv)
  85. int argc;
  86. char *argv[];
  87. {
  88.     int x;
  89.     if (argc < 2)
  90.         printf("%d\n",smtpmaxcli);
  91.     else {
  92.         x = atoi(argv[1]);
  93.         if (x > MAXSESSIONS)
  94.             printf("max clients must be <= %d\n",MAXSESSIONS);
  95.         else
  96.             smtpmaxcli = x;
  97.     }
  98.     return 0;
  99. }
  100.  
  101. static int
  102. setsmtpmode(argc,argv)
  103. int argc;
  104. char *argv[];
  105. {
  106.     if (argc < 2) {
  107.         printf("smtp mode: %s\n",
  108.             (Smtpmode & QUEUE) ? "queue" : "route");
  109.     } else {
  110.         switch(*argv[1]) {
  111.         case 'q':
  112.             Smtpmode |= QUEUE;
  113.             break;
  114.         case 'r':
  115.             Smtpmode &= ~QUEUE;
  116.             break;
  117.         default:
  118.             printf("Usage: smtp mode [queue | route]\n");
  119.             break;
  120.         }
  121.     }
  122.     return 0;
  123. }
  124. static int
  125. dogateway(argc,argv)
  126. int argc;
  127. char *argv[];
  128. {
  129.     int32 n;
  130.  
  131.     if(argc < 2){
  132.         printf("%s\n",inet_ntoa(gateway));
  133.     } else if((n = resolve(argv[1])) == 0){
  134.         printf(Badhost,argv[1]);
  135.         return 1;
  136.     } else
  137.         gateway = n;
  138.     return 0;
  139. }
  140.  
  141. #ifdef SMTPTRACE
  142. static int
  143. dosmtptrace(argc,argv)
  144. int argc;
  145. char *argv[];
  146. {
  147.     if (argc < 2)
  148.         printf("%d\n",Smtptrace);
  149.     else 
  150.         Smtptrace = atoi(argv[1]);
  151.     return 0;
  152. }
  153. #endif
  154.  
  155. /* Set outbound spool scan interval */
  156. static int
  157. dotimer(argc,argv)
  158. int argc;
  159. char *argv[];
  160. {
  161.     if(argc < 2){
  162.         printf("%lu/%lu\n",
  163.         (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
  164.         smtpcli_t.start/(1000/MSPTICK));
  165.         return 0;
  166.     }
  167.     smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  168.     smtpcli_t.arg = NULLCHAR;        /* dummy value */
  169.     smtpcli_t.start = atol(argv[1])*(1000/MSPTICK);    /* set timer duration */
  170.     start_timer(&smtpcli_t);        /* and fire it up */
  171.     return 0;
  172. }
  173.  
  174. /* this is the routine that gets called every so often to do outgoing mail
  175.    processing */
  176. int
  177. smtptick()
  178. {
  179.     register struct smtpcli *cb;
  180.     struct smtp_job *jp;
  181.     struct list *ap;
  182.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  183.     char    from[LINELEN], to[LINELEN];
  184.     char *cp, *cp1;
  185.     int32 destaddr;
  186.     FILE *wfile;
  187.  
  188. #ifdef SMTPTRACE
  189.     if (Smtptrace > 5)
  190.         printf("smtp daemon entered\n");
  191. #endif
  192.     for(filedir(Mailqueue,0,wfilename);wfilename[0] != '\0';
  193.         filedir(Mailqueue,1,wfilename)){
  194.  
  195.         /* save the prefix of the file name which it job id */
  196.         cp = wfilename;
  197.         cp1 = prefix;
  198.         while (*cp && *cp != '.')
  199.             *cp1++ = *cp++;
  200.         *cp1 = '\0';
  201.  
  202.         /* lock this file from the smtp daemon */
  203.         if (mlock(Mailqdir,prefix))
  204.             continue;
  205.  
  206.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  207.         if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
  208.             /* probably too many open files */
  209.             (void) rmlock(Mailqdir,prefix);
  210.             /* continue to next message. The failure
  211.             * may be temporary */
  212.             continue;
  213.         }
  214.  
  215.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  216.         rip(tmpstring);
  217.  
  218.         if ((destaddr = mailroute(tmpstring)) == 0) {
  219.             fclose(wfile);
  220.             printf("** smtp: Unknown address %s\n",tmpstring);
  221.             (void) rmlock(Mailqdir,prefix);
  222.             continue;
  223.         }
  224.  
  225.         if ((cb = lookup(destaddr)) == NULLSMTPCLI) {
  226.             /* there are enough processes running already */
  227.             if (smtpsessions >= smtpmaxcli) {
  228. #ifdef SMTPTRACE
  229.                 if (Smtptrace) {
  230.                     printf("smtp daemon: too many processes\n");
  231.                 }
  232. #endif
  233.                 fclose(wfile);
  234.                 (void) rmlock(Mailqdir,prefix);
  235.                 break;
  236.             }
  237.             if ((cb = newcb()) == NULLSMTPCLI) {
  238.                 fclose(wfile);
  239.                 (void) rmlock(Mailqdir,prefix);
  240.                 break;
  241.             } 
  242.             cb->ipdest = destaddr;
  243.         } else {
  244.             /* This system is already is sending mail lets not
  245.             * interfere with its send queue.
  246.             */
  247.             if (cb->state != CLI_INIT_STATE) {
  248.                 fclose(wfile);
  249.                 (void) rmlock(Mailqdir,prefix);
  250.                 continue;
  251.             }
  252.         }
  253.  
  254.         (void) fgets(from,LINELEN,wfile);    /* read from */
  255.         rip(from);
  256.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  257.             fclose(wfile);
  258.             (void) rmlock(Mailqdir,prefix);
  259.             del_session(cb);
  260.             break;
  261.         }
  262.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  263.             rip(to);
  264.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  265.                 fclose(wfile);
  266.                 del_session(cb);
  267.             }
  268.         }
  269.         fclose(wfile);
  270. #ifdef SMTPTRACE
  271.         if (Smtptrace > 1) {
  272.             printf("queue job %s From: %s To:",prefix,from);
  273.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  274.                 printf(" %s",ap->val);
  275.             printf("\n");
  276.         }
  277. #endif
  278.     }
  279.  
  280.     /* start sending that mail */
  281.     execjobs();
  282.  
  283.     /* Restart timer */
  284.     start_timer(&smtpcli_t);
  285.     return 0;
  286. }
  287.  
  288. /* this is the master state machine that handles a single SMTP transaction */
  289. /* it is called with a queue of jobs for a particular host. */
  290. static void
  291. smtp_send(unused,cb)
  292. int unused;
  293. register struct smtpcli *cb;
  294. {
  295.     register char reply;
  296.     register struct list *tp;
  297.     struct sockaddr_in fsocket;
  298.     struct mbuf *bp,*bpl;
  299.     char *cp;
  300.     char tbuf[LINELEN];
  301.     int rcode;
  302.  
  303.     fsocket.sin_family = AF_INET;
  304.     fsocket.sin_addr.s_addr = cb->ipdest;
  305.     fsocket.sin_port = IPPORT_SMTP;
  306.  
  307.     cb->s = socket(AF_INET,SOCK_STREAM,0);
  308.     cb->state = CLI_OPEN_STATE;    /* init state placeholder */
  309. #ifdef SMTPTRACE
  310.     if (Smtptrace) 
  311.         printf("SMTP client Trying...\n");
  312. #endif
  313.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == 0){
  314. #ifdef SMTPTRACE
  315.     if (Smtptrace) 
  316.         printf("Connected\n");
  317. #endif
  318.         ;
  319.     } else {
  320.         cp = sockerr(cb->s);
  321. #ifdef SMTPTRACE
  322.         if (Smtptrace) 
  323.             printf("Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  324. #endif
  325.         log(cb->s,"Connect failed: %s\n",cp != NULLCHAR ? cp : "");
  326.     }
  327.  
  328.     while(1) {
  329.         
  330.         if (recvline(cb->s,cb->buf,LINELEN) == -1)
  331.             goto quit;
  332.         rip(cb->buf);
  333. #ifdef SMTPTRACE
  334.         if (Smtptrace)
  335.             printf("smtp rcvd: '%s'\n",cb->buf);
  336. #endif
  337.  
  338.         /* Another line follows, ignore this one */
  339.         if(cb->buf[0] == '0' || cb->buf[3] == '-')
  340.             continue;
  341.  
  342.         reply = cb->buf[0];
  343.         rcode = atoi(cb->buf);
  344.  
  345.         /* if service shuting down */
  346.         if (rcode == 421) {
  347.             sendquit(cb);
  348.             continue;
  349.         }
  350.  
  351.         switch(cb->state) {
  352.         case CLI_OPEN_STATE:
  353.             if (reply != '2')
  354.                 sendquit(cb);
  355.             else {
  356.                 cb->state = CLI_HELO_STATE;
  357.                 sendcmd(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  358.                 Hostname,cb->jobq->from);
  359.             }
  360.             break;
  361.         case CLI_HELO_STATE:
  362.             if (reply != '2')
  363.                 sendquit(cb);
  364.             else 
  365.                 cb->state = CLI_MAIL_STATE;
  366.             break;            
  367.         case CLI_MAIL_STATE:
  368.             if (reply != '2')
  369.                 sendquit(cb);
  370.             else {
  371.                 cb->state = CLI_RCPT_STATE;
  372.                 cb->rcpts = 0;
  373.                 bpl = NULLBUF;
  374.                 for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  375.                     sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  376.                     bp = qdata(tbuf,(int16)strlen(tbuf));
  377.                     if (bp == NULLBUF) {
  378.                         free_p(bpl);
  379.                         sendquit(cb);
  380.                         goto quit;
  381.                     }
  382.                     append(&bpl,bp);
  383.                     cb->rcpts++;
  384. #ifdef SMTPTRACE
  385.                     if (Smtptrace) {
  386.                         printf("smtp sent: %s",tbuf);
  387.                     }
  388. #endif
  389.                 }
  390.                 send_mbuf(cb->s,bpl,0,NULLCHAR,0);
  391.             }
  392.             break;
  393.         case CLI_RCPT_STATE:
  394.             if (reply == '5') {
  395.                 logerr(cb);
  396.             } else if (reply == '2') {
  397.                 cb->goodrcpt = 1;
  398.             } else {
  399.                 /* some kind of temporary failure */
  400.                 abort_trans(cb);
  401.                 break;
  402.             }
  403.             /* if more rcpts stay in this state */
  404.             if (--cb->rcpts != 0)
  405.                 break;
  406.  
  407.             /* check for no good rcpt on the list */
  408.             if (cb->goodrcpt == 0) {
  409.                 if (cb->errlog != NULLLIST)
  410.                     retmail(cb);
  411.                 (void) unlink(cb->wname);    /* unlink workfile */
  412.                 (void) unlink(cb->tname);    /* unlink text */
  413.                 abort_trans(cb);
  414.                 break;
  415.             }
  416.             /* if this file open fails abort */
  417.             if ((cb->tfile = fopen(cb->tname,"r")) == NULLFILE)
  418.                 abort_trans(cb);
  419.             else {
  420.                 sendcmd(cb,"DATA\r\n");
  421.                 cb->state = CLI_SEND_STATE;
  422.             }
  423.             break;
  424.         case CLI_SEND_STATE:
  425.             if (reply == '3') {
  426.                 cb->state = CLI_UNLK_STATE;
  427.                 sendfile(cb);
  428.             } else {
  429.                 sendquit(cb);
  430.             }
  431.             break;
  432.         case CLI_UNLK_STATE:
  433.             /* if a good transfer or permanent failure remove job */
  434.             if (reply == '2' || reply == '5') {
  435.                 if (reply == '5')
  436.                     logerr(cb);
  437.                 /* close and unlink the textfile */
  438.                 if(cb->tfile != NULLFILE) {
  439.                     fclose(cb->tfile);
  440.                     cb->tfile = NULLFILE;
  441.                 }
  442.                 if (cb->errlog != NULLLIST)
  443.                     retmail(cb);
  444.                 (void) unlink(cb->tname);
  445.                 (void) unlink(cb->wname);    /* unlink workfile */
  446.                 log(cb->s,"SMTP sent job %s To: %s From: %s",
  447.                 cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  448.             }
  449.             if (next_job(cb)) {
  450.                 cb->state = CLI_MAIL_STATE;
  451.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  452.             } else {
  453.                 sendquit(cb);
  454.                 cb->state = CLI_QUIT_STATE;
  455.             }
  456.             break;
  457.         case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  458.             if (reply != '2')
  459.                 sendquit(cb);
  460.             else {
  461.                 cb->state = CLI_MAIL_STATE;
  462.                 sendcmd(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  463.             }
  464.             break;            
  465.         case CLI_QUIT_STATE:
  466.             goto quit;
  467.             break;
  468.         }
  469.     }
  470. quit:
  471.     (void) close_s(cb->s);
  472.     if(cb->tfile != NULLFILE)
  473.         fclose(cb->tfile);
  474.     del_session(cb);
  475. }
  476.  
  477. /* abort the currrent job.
  478.  * If more work exists set up the next job if
  479.  * not then shut down.
  480. */
  481. static void
  482. abort_trans(cb)
  483. register struct smtpcli *cb;
  484. {
  485. #ifdef SMTPSTRACE
  486.     if (Smtptrace)
  487.         printf("smtpcli: abort transaction\n");
  488. #endif
  489.     if(cb->tfile != NULLFILE) {
  490.         fclose(cb->tfile);
  491.         cb->tfile = NULLFILE;
  492.     }
  493.     if (next_job(cb)) {
  494.         sendcmd(cb,"RSET\r\n");
  495.         cb->state = CLI_IDLE_STATE;
  496.     } else 
  497.         sendquit(cb);
  498. }
  499.  
  500. void
  501. static sendquit(cb)
  502. struct smtpcli *cb;
  503. {
  504.     cb->state = CLI_QUIT_STATE;
  505.     sendcmd(cb,quitcmd);    /* issue a quit command */
  506. }
  507.  
  508. /* Send message back to server */
  509. /*VARARGS*/
  510. static void
  511. sendcmd(cb,fmt,arg1,arg2)
  512. struct smtpcli *cb;
  513. char *fmt,*arg1,*arg2;
  514. {
  515.     struct mbuf *bp;
  516.     char tmpstring[256];
  517.  
  518. #ifdef SMTPTRACE
  519.     if (Smtptrace) {
  520.         printf("smtp sent: ");
  521.         printf(fmt,arg1,arg2);
  522.     }
  523. #endif
  524.     sprintf(tmpstring,fmt,arg1,arg2);
  525.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  526.     send_mbuf(cb->s,bp,0,NULLCHAR,0);
  527. }
  528.  
  529. /* create mail lockfile */
  530. int
  531. mlock(dir,id)
  532. char *dir,*id;
  533. {
  534.     char lockname[LINELEN];
  535.     int fd;
  536.  
  537.     /* Try to create the lock file in an atomic operation */
  538.     sprintf(lockname,"%s/%s.lck",dir,id);
  539.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  540.         return -1;
  541.     close(fd);
  542.     return 0;
  543. }
  544.  
  545. /* remove mail lockfile */
  546. int
  547. rmlock(dir,id)
  548. char *dir,*id;
  549. {
  550.     char lockname[LINELEN];
  551.     sprintf(lockname,"%s/%s.lck",dir,id);
  552.     return(unlink(lockname));
  553. }
  554.  
  555. /* free the message struct and data */
  556. static void
  557. del_session(cb)
  558. register struct smtpcli *cb;
  559. {
  560.     register struct smtp_job *jp,*tp;
  561.     register int i;
  562.  
  563.     if (cb == NULLSMTPCLI)
  564.         return;
  565.     for(i=0; i<MAXSESSIONS; i++) 
  566.         if(cli_session[i] == cb) {
  567.             cli_session[i] = NULLSMTPCLI;
  568.             break;
  569.         }
  570.  
  571.     if(cb->wname != NULLCHAR)
  572.         free(cb->wname);
  573.     if(cb->tname != NULLCHAR)
  574.         free(cb->tname);
  575.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  576.             tp = jp->next;
  577.             del_job(jp);
  578.     }
  579.     del_list(cb->errlog);
  580.     free((char *)cb);
  581.     smtpsessions--;    /* number of connections active */
  582. }
  583.  
  584. static void
  585. del_job(jp)
  586. register struct smtp_job *jp;
  587. {
  588.     if ( *jp->jobname != '\0')
  589.         (void) rmlock(Mailqdir,jp->jobname);
  590.     if(jp->from != NULLCHAR)
  591.         free(jp->from);
  592.     del_list(jp->to);
  593.     free((char *)jp);
  594. }
  595.  
  596. /* delete a list of list structs */
  597. void
  598. del_list(lp)
  599. struct list *lp;
  600. {
  601.     register struct list *tp, *tp1;
  602.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  603.             tp1 = tp->next;
  604.             if(tp->val != NULLCHAR)
  605.                 free(tp->val);
  606.             free((char *)tp);
  607.     }
  608. }
  609.  
  610. /* return message to sender */
  611. static void
  612. retmail(cb)
  613. struct smtpcli *cb;
  614. {
  615.     register struct list *lp;
  616.     register FILE *tfile;
  617.     register int c;
  618.     FILE *infile;
  619.     char *to;
  620.     time_t t;
  621.     
  622. #ifdef SMTPTRACE
  623.     if (Smtptrace > 5) {
  624.         printf("smtp job %s returned to sender\n",cb->wname);
  625.     }
  626. #endif
  627.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  628.     to = cb->jobq->from;
  629.     if (*to == '\0')
  630.         return;
  631.     if ((infile = fopen(cb->tname,"r")) == NULLFILE)
  632.         return;
  633.     if ((tfile = tmpfile()) == NULLFILE) {
  634.         fclose(infile);
  635.         return;
  636.     }
  637.     time(&t);
  638.     fprintf(tfile,"Date: %s",ptime(&t));
  639.     fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),Hostname);
  640.     fprintf(tfile,"From: MAILER-DAEMON@%s\n",Hostname);
  641.     fprintf(tfile,"To: %s\n",to);
  642.     fprintf(tfile,"Subject: Failed mail\n\n");
  643.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  644.  
  645.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  646.         fprintf(tfile,"%s\n",lp->val);
  647.  
  648.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  649.  
  650.     while((c = getc(infile)) != EOF)
  651.         if (putc(c,tfile) == EOF)
  652.             break;
  653.     fclose(infile);
  654.     fseek(tfile,0L,0);
  655.     (void) mailuser(tfile,"",to);
  656.     fclose(tfile);
  657. }
  658.  
  659. /* look to see if a smtp control block exists for this ipdest */
  660. static struct smtpcli *
  661. lookup(destaddr)
  662. int32 destaddr;
  663. {
  664.     register int i;
  665.  
  666.     for(i=0; i<MAXSESSIONS; i++) {
  667.         if (cli_session[i] == NULLSMTPCLI)
  668.             continue;
  669.         if(cli_session[i]->ipdest == destaddr)
  670.             return cli_session[i];
  671.     }
  672.     return NULLSMTPCLI;
  673. }
  674.  
  675. /* create a new  smtp control block */
  676. static struct smtpcli *
  677. newcb()
  678. {
  679.     register int i;
  680.     register struct smtpcli *cb;
  681.  
  682.     for(i=0; i<MAXSESSIONS; i++) {
  683.         if(cli_session[i] == NULLSMTPCLI) {
  684.             cb = (struct smtpcli *)calloc(1,sizeof(struct smtpcli));
  685.             if (cb == NULLSMTPCLI)
  686.                 return(NULLSMTPCLI);
  687.             cb->wname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  688.             if (cb->wname == NULLCHAR) {
  689.                 free((char *)cb);
  690.                 return(NULLSMTPCLI);
  691.             }
  692.             cb->tname = malloc((unsigned)strlen(Mailqdir)+JOBNAME);
  693.             if (cb->tname == NULLCHAR) {
  694.                 free(cb->wname);
  695.                 free((char *)cb);
  696.                 return(NULLSMTPCLI);
  697.             }
  698.             cb->state = CLI_INIT_STATE;
  699.             cli_session[i] = cb;
  700.             smtpsessions++;    /* number of connections active */
  701.             return(cb);
  702.         }
  703.     }
  704.     return NULLSMTPCLI;
  705. }
  706.  
  707. static void
  708. execjobs()
  709. {
  710.     register struct smtpcli *cb;
  711.     register int i;
  712.  
  713.     for(i=0; i<MAXSESSIONS; i++) {
  714.         cb = cli_session[i];
  715.         if (cb == NULLSMTPCLI) 
  716.             continue;
  717.         if(cb->state != CLI_INIT_STATE)
  718.             continue;
  719.  
  720.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  721.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  722.  
  723.         newproc("smtp_send", 1024, smtp_send, 0, cb);
  724.  
  725. #ifdef SMTPTRACE
  726.         if (Smtptrace) 
  727.             printf("Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  728. #endif
  729.  
  730.  
  731.     }
  732. }
  733.     
  734. /* add this job to control block queue */
  735. static struct smtp_job *
  736. setupjob(cb,id,from)
  737. struct smtpcli *cb;
  738. char *id,*from;
  739. {
  740.     register struct smtp_job *p1,*p2;
  741.  
  742.     p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  743.     if (p1 == NULLJOB)
  744.         return NULLJOB;
  745.     p1->from = malloc((unsigned)strlen(from) + 1);
  746.     if (p1->from == NULLCHAR) {
  747.         free((char *)p1);
  748.         return NULLJOB;
  749.     }
  750.     strcpy(p1->from,from);
  751.     strcpy(p1->jobname,id);
  752.     /* now add to end of jobq */
  753.     if ((p2 = cb->jobq) == NULLJOB)
  754.         cb->jobq = p1;
  755.     else {
  756.         while(p2->next != NULLJOB)
  757.             p2 = p2->next;
  758.         p2->next = p1;
  759.     }
  760.     return p1;
  761. }
  762.  
  763. /* called to advance to the next job */
  764. static int
  765. next_job(cb)
  766. register struct smtpcli *cb;
  767. {
  768.     register struct smtp_job *jp;
  769.  
  770.     jp = cb->jobq->next;
  771.     del_job(cb->jobq);
  772.     if (jp == NULLJOB) {
  773.         cb->jobq = NULLJOB;
  774.         return 0;
  775.     }
  776.     /* remove the error log of previous message */
  777.     del_list(cb->errlog);
  778.     cb->errlog = NULLLIST;
  779.     cb->goodrcpt = 0;
  780.     cb->jobq = jp;
  781.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  782.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  783. #ifdef SMTPTRACE
  784.     if (Smtptrace > 5) {
  785.         printf("sending job %s\n",jp->jobname);
  786.     }
  787. #endif
  788.         return 1;
  789.  
  790. }
  791.  
  792.  
  793. /* mail routing funtion. For now just used the hosts file */
  794. int32 mailroute(dest)
  795. char *dest;
  796. {
  797.     int32 destaddr;
  798.  
  799.     /* look up address or use the gateway */
  800.     if ((destaddr = resolve(dest)) == 0)
  801.         if (gateway != 0) 
  802.             destaddr = gateway; /* Use the gateway  */
  803.     return destaddr;
  804.     
  805. }
  806.  
  807. /* save error reply for in error list */
  808. static void
  809. logerr(cb)
  810. struct smtpcli *cb;
  811. {
  812.     register struct list *lp,*tp;
  813.     if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  814.         return;
  815.     if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  816.         free((char *)tp);
  817.         return;
  818.     }
  819.     /* find end of list */
  820.     if ((lp = cb->errlog) == NULLLIST)
  821.         cb->errlog = tp;
  822.     else {
  823.         while(lp->next != NULLLIST)
  824.             lp = lp->next;
  825.         lp->next = tp;
  826.     }
  827.     strcpy(tp->val,cb->buf);
  828. }
  829.  
  830. static int
  831. sendfile(cb)
  832. register struct smtpcli *cb;
  833. {
  834.     register int c;
  835.     char *cp;
  836.     register struct mbuf *bp;
  837.     int sawnl = 1;
  838.     int error = 0;
  839.  
  840.     for(;;) {
  841.         /* Hard to know what to do here */
  842.         if ((bp = alloc_mbuf(BUFSIZ)) == NULLBUF)
  843.             return EOF;
  844.         cp = bp->data;
  845.         while((c = fgetc(cb->tfile)) != EOF && bp->cnt < BUFSIZ-2){
  846.             if (c == '\r')    /* strip cr from some pc hosts */
  847.                 continue;
  848.             if (c == '\n') { /* send line end as \r\n */
  849.                 *cp++ = '\r';
  850.                 bp->cnt++;
  851.                 sawnl = 1;
  852.             } else {
  853.         /* special case of a line with just a . sent as ..  one it */
  854.                 if (c == '.' && sawnl) {
  855.                     c = fgetc(cb->tfile);
  856.                     if ( c != EOF && c != '\n' && c != '\r')
  857.                         ungetc(c,cb->tfile);
  858.                     else {
  859.                         *cp++ = '.';
  860.                         bp->cnt++;
  861.                     }
  862.                     c = '.';
  863.                 }
  864.                 sawnl = 0;
  865.             }
  866.             *cp++ = c;
  867.             bp->cnt++;
  868.         }                
  869.         if(bp->cnt != 0) {
  870.             if(send_mbuf(cb->s,bp,0,NULLCHAR,0) == -1){
  871.                 error = 1;
  872.                 break;
  873.             }
  874.         } else {
  875.             free_p(bp);
  876.             break;
  877.         }
  878.     }
  879.     fclose(cb->tfile);
  880.     cb->tfile = NULLFILE;
  881.     sendcmd(cb,eom);
  882.     return error;
  883. }
  884.